
# -*- coding: utf-8 -*-
# from mcp.server.fastmcp import FastMCP
from bilibili_api import search
from bilibili_api.comment import CommentResourceType
from bilibili_api.search import SearchObjectType
import asyncio
from urllib.parse import urlparse
from bilibili_api import video,Credential
from bilibili_api import comment, sync
from mcp.server import FastMCP
from playwright.async_api import async_playwright, expect #异步方式输入
import json
#instructions告诉MCP这个MCPServer是做什么的。
app = FastMCP("bilibili-mcp-server",instructions="bilibili(也称：B站)的MCP Server,能自动实现登录、获取视频评论、点赞等功能。")

def _exact_bvid(url_or_bvid):
    if url_or_bvid.startswith("http"):
        bvid = urlparse(url_or_bvid).path.strip("/").split("/")[-1]
    else:
        bvid = url_or_bvid
    return bvid

@app.tool()
async def search_video(keyword: str, page: int = 1):
    """
    在B站上搜索指定关键字的视频
    :param keyword: 用户输入的关键字
    :param page: 页码
    :return: 在B站搜索后的结果
    """
    result =  await search.search_by_type(keyword=keyword, page=page, search_type=SearchObjectType.VIDEO)

    return_result = {
        "page": page,
        "page_size": result['pagesize'],
        "num_pages": result['numPages'],
        "videos": [
            {
                "id": video['id'],
                "author": video['author'],
                "bvid": video["bvid"],
                "title": video['title'],
                "description": video["description"],
                "tag": video["tag"],
                "pubdate": video['pubdate'],
                "duration": video['duration'],
                "like": video['like'],
                "play":video['play']
            }
            for video in result['result']
        ]
    }
    return return_result

@app.tool()
async def login_bilibili(mobile: str, password: str):
    """
    输入手机号和密码来登录bilibili，登录过程中可能需要用户自己处理图形验证码和短信验证码，登录成功则返回
    cookie信息，登录失败则返回None
    :param mobile: 登录的手机号
    :param password: 登录的密码
    :return: 如果登录成功，则返回登录成功后的cookie；如果登录失败，则返回None
    """
    async with async_playwright() as p:
        browser = await p.chromium.launch(headless=False)
        context = await browser.new_context()
        page = await context.new_page()
        await page.goto("https://www.bilibili.com")

        # 1. 等待页面完全加载（包括动态内容）
        await page.wait_for_load_state("networkidle",timeout=20000)

        try:
            # 定位登录按钮并确保其在 DOM 中存在
            login_button = await page.wait_for_selector(
                'text=登录',
                state="attached",  # 确保元素在 DOM 中
                timeout=10000
            )

            # 使用 JavaScript 强制点击，绕过遮挡
            await login_button.evaluate('(el) => el.click()')

        except TimeoutError:
            print("登录按钮仍未找到或已脱离 DOM")
            await page.screenshot(path="login_button_undetached.png")
            raise

        print("-------------------------------3")
        # 3. 寻找账号/密码的输入框并输入内容
        await page.get_by_placeholder(text="请输入账号").fill(mobile)
        await page.get_by_placeholder(text="请输入密码").fill(password)
        print("-------------------------------4")
        # 4. 找到登录按钮并执行点击操作
        await page.locator(".btn_primary").click()
        print("--------------找到登录按钮并执行点击操作")
        # 先等待验证码界面出现
        await page.wait_for_selector(selector=".geetest_widget", state="visible")
        print("-------------------------------5")
        # 2Captcha
        # 等待用户操作验证码（验证码界面显示）
        await page.wait_for_selector(selector=".geetest_widget", state="hidden")
        print("-------------------------------6")
        # 图形验证码操作完成后，如果账号有异常，可能还需要跳转到短信验证码的页面
        # 等待页面跳转到首页
        await page.wait_for_timeout(3000)
        print("-------------------------------7")
        # 再判断是否到首页了
        await expect(page).to_have_title("哔哩哔哩 (゜-゜)つロ 干杯~-bilibili", timeout=30000)
        print("-------------------------------8")
        # 代码走到这里来了，说明已经到首页了，也就意味着登录成功了
        # 获取cookie
        cookies = await context.cookies()
        print("-------------------------------9")
        return_cookies = {}
        for cookie in cookies:
            if cookie['name'] == 'SESSDATA':
                return_cookies['SESSDATA'] = cookie['value']
            elif cookie['name'] == 'bili_jct':
                return_cookies['bili_jct'] = cookie['value']

        return return_cookies


@app.tool()
async def like_video(url_or_bvid: str, SESSDATA: str, bili_jct: str):
    """
    给bilibili指定的视频点赞。此操作必须要登录后才能执行，SESSDATA和bili_jct是登录后bilibili返回的
    cookie信息
    :param url_or_bvid: 视频的url或对应的BVID
    :param SESSDATA: SESSDATA信息，登录成功后返回的cookie中获取
    :param bili_jct: bili_jct信息，登录成功后返回的cookie中获取
    :return: 如果点赞成功，则返回True；否则返回错误信息
    """
    try:
        bvid=_exact_bvid(url_or_bvid)
        credential = Credential(sessdata=SESSDATA, bili_jct=bili_jct)
        v = video.Video(bvid=bvid, credential=credential)
        await v.like(status=True)
        return True
    except Exception as e:
        return str(e)


@app.tool()
async def send_comment(url_or_bvid: str, text: str, SESSDATA: str, bili_jct: str):
    try:
        bvid = _exact_bvid(url_or_bvid)
        v = video.Video(bvid=bvid)
        video_info = await v.get_info()
        credential = Credential(sessdata=SESSDATA, bili_jct=bili_jct)
        result = await comment.send_comment(text=text, oid=video_info['aid'],
                                            type_=CommentResourceType.VIDEO, credential=credential)
        return True
    except Exception as e:
        return str(e)


'''
测试搜索视频接口
async def main():
    result = await search_video("钢铁侠")
    print(result)
if __name__ == '__main__':
    app.run(transport="stdio")
    #asyncio.run(main())
'''
'''
#测试采用手机号登录bilibili
async def main():
    result = await login_bilibili(mobile="18701381625", password='Zhang1@yang')
    print(result)
if __name__ == '__main__':
    asyncio.run(main())

'''

'''
#发表评论
async def main():
    cookie = await login_bilibili(mobile="18515287309", password='haha1111')
    await send_comment("https://www.bilibili.com/video/BV1UJL1zcE2S/?spm_id_from=333.337.search-card.all.click&vd_source=0268b3d3304755717edd31291e5ba0b8", SESSDATA=cookie['SESSDATA'], bili_jct=cookie['bili_jct'], text="我爱钢铁侠！")
    
'''

#MCP
async def main():
    result = await login_bilibili(mobile="18701381625", password='Zhang1@yang')
    print(result)

if __name__ == '__main__':
    #asyncio.run(main())
    app.run(transport="stdio")
